"""
ReadMe：
此脚本主要实现公司运营管理部要求的每月上报的数据质量
包括：
1.当月工作量以及累积工作量
2.截止每月底时的COPQ
3.计算每月的低星版本率（建设中...）
"""
import os

import chardet
import pandas as pd


# 通过输入路径，获取路径下文件的数据并合并返回一个dataFrame对象
def get_date(path):
    # 调用get_file_list()方法获取文件名列表
    file_list = get_file_list(path)
    # 读取第一个文件的编码类型
    file_encoding = check_file_encoding(path + file_list[0])
    # 调用get_file_content()方法获取文件内容，返回DataFrame对象file_content
    file_content = get_file_content(path, file_list, file_encoding)

    return file_content


def cal_lowStars(file_contetn):
    """
    计算低星版本率
    """

def cal_month_childproject(file_content):
    """
    计算每个项目的子项目工作量
    """
    # 根据“日期”列生成“月份”列
    file_content['月份'] = file_content['日期'].apply(lambda x: x[:4] + x[5:7])
    # 提取file_content中项目、月份、小时列的数据
    file_content = file_content[['类别', '日期', '小时', '月份']]
    # 按“项目”和“月份”对file_content中的“小时”列进行汇总
    grouped = file_content.groupby(['类别', '月份'])['小时'].sum().rename('合计工时')
    # 重新使grouped成为DataFrame以便于后续的计算
    grouped = grouped.reset_index()

    # 读取法定工作日表
    workdays = pd.read_excel('./Files/workLoad/2024年法定工作日.xlsx')
    # 将workdays中的月份转换成str类型
    workdays['月份'] = workdays['月份'].astype(str)
    # 以grouped为基准，与workdays进行左链接合并
    merge_df = pd.merge(grouped, workdays, on='月份', how='left')
    # 新增计算人月工作量，计算公式：合计工时列除以8后，再除以法定工作日列，并保留两位小数
    merge_df['人月工作量'] = merge_df.apply(lambda row: round(row['合计工时'] / 8 / row['法定工作日'], 2), axis=1)

    # 对集合按项目进行去重并循环
    unique_project_list = merge_df.drop_duplicates(subset='类别')['类别'].to_list()
    # 创建一个ExcelWriter对象，制定输出文件名
    writer = pd.ExcelWriter('E:/工作文件/运营管理部 项目指标/工作量/运营管理部/' + '各子项目工作量统计（运营管理部）.xlsx')
    # 对集合进行循环遍历后，将不同的项目信息分别保存至不同的sheet页
    for project in unique_project_list:
        # 以项目为条件对merge_df进行过滤
        filter_df = merge_df[merge_df['类别'] == project].groupby(['类别', '月份'])['人月工作量'].sum().rename(
            '当月工作量合计（人月）')
        filter_df = filter_df.reset_index()
        filter_df['累积工作量合计（人月）'] = filter_df['当月工作量合计（人月）'].cumsum()
        # print(filter_df)
        # print()
        # 将过滤后的数据保存至Excel的sheet页中
        filter_df.to_excel(writer, sheet_name=project, index=False)
    writer.close()

# 1.计算每个月的工作量和累积的工作量
# 2.将不同的项目分别保存至Excel的不同的sheet页中
def cal_month_data(file_content):
    """
    计算每月数据质量
    """
    # 根据“日期”列生成“月份”列
    file_content['月份'] = file_content['日期'].apply(lambda x: x[:4] + x[5:7])
    # 提取file_content中项目、月份、小时列的数据
    file_content = file_content[['项目', '日期', '小时', '月份']]

    """
    1.因为“汽车数字化项目”存在两个Redmine记录工作量且数据结构并不完全一致，所以此段代码针对旧Redmine的数据进行处理
    2.其他项目不使用可以将此段代码注释掉
    3.从此处开始
    """
    file_old_content = get_date('E:/工作文件/运营管理部 项目指标/工作量/旧数据/')
    file_old_content['月份'] = file_old_content['日期'].apply(lambda x: x[:4] + x[5:7])
    file_old_content['项目'] = 'RD008001.汽车数字化分析'
    file_old_content = file_old_content[['项目', '日期', '小时', '月份']]
    # 将file_old_content接在file_content的后面
    file_content = pd.concat([file_content, file_old_content])
    """
    4.从此处结束
    """

    # 按“项目”和“月份”对file_content中的“小时”列进行汇总
    grouped = file_content.groupby(['项目', '月份'])['小时'].sum().rename('合计工时')
    # 重新使grouped成为DataFrame以便于后续的计算
    grouped = grouped.reset_index()

    # 读取法定工作日表
    workdays = pd.read_excel('./Files/workLoad/2024年法定工作日.xlsx')
    # 将workdays中的月份转换成str类型
    workdays['月份'] = workdays['月份'].astype(str)
    # 以grouped为基准，与workdays进行左链接合并
    merge_df = pd.merge(grouped, workdays, on='月份', how='left')
    # 新增计算人月工作量，计算公式：合计工时列除以8后，再除以法定工作日列，并保留两位小数
    merge_df['人月工作量'] = merge_df.apply(lambda row: round(row['合计工时'] / 8 / row['法定工作日'], 5), axis=1)

    # 对集合按项目进行去重并循环
    unique_project_list = merge_df.drop_duplicates(subset='项目')['项目'].to_list()
    # 创建一个ExcelWriter对象，制定输出文件名
    writer = pd.ExcelWriter('E:/工作文件/运营管理部 项目指标/工作量/运营管理部/' + '各项目工作量统计（运营管理部）.xlsx')
    # 对集合进行循环遍历后，将不同的项目信息分别保存至不同的sheet页
    for project in unique_project_list:
        # 以项目为条件对merge_df进行过滤
        filter_df = merge_df[merge_df['项目'] == project].groupby(['项目', '月份'])['人月工作量'].sum().rename(
            '当月工作量合计（人月）')
        filter_df = filter_df.reset_index()
        filter_df['累积工作量合计（人月）'] = filter_df['当月工作量合计（人月）'].cumsum()
        # print(filter_df)
        # print()
        # 将过滤后的数据保存至Excel的sheet页中
        filter_df.to_excel(writer, sheet_name=project, index=False)
    writer.close()


def cal_copq(file_content):
    """
    计算COPQ
    """
    # 根据“日期”列生成“月份”列
    file_content['月份'] = file_content['日期'].apply(lambda x: x[:4] + x[5:7])
    # 提取file_content中项目、月份、小时列的数据
    file_content = file_content[['项目', '日期', '小时', '月份', '跟踪']]

    """
    1.因为“汽车数字化项目”存在两个Redmine记录工作量且数据结构并不完全一致，所以此段代码针对旧Redmine的数据进行处理
    2.其他项目不使用可以将此段代码注释掉
    3.从此处开始
    """
    file_old_content = get_date('E:/工作文件/运营管理部 项目指标/工作量/旧数据/')
    file_old_content['月份'] = file_old_content['日期'].apply(lambda x: x[:4] + x[5:7])
    file_old_content['项目'] = 'RD008001.汽车数字化分析'
    # file_old_content中，“Bug等级”列不为空的，内容更新成“Bug-ST”

    levels = ['S', 'A', 'B', 'C', 'D']
    file_old_content.loc[file_old_content['Bug等级'].isin(levels), '跟踪'] = 'Bug-ST'

    file_old_content = file_old_content[['项目', '日期', '小时', '月份', '跟踪']]
    # 将file_old_content接在file_content的后面
    file_content = pd.concat([file_content, file_old_content])
    """
    4.从此处结束
    """

    # 按“项目”和“月份”对file_content中的“小时”列进行汇总
    grouped = file_content.groupby(['项目', '月份'])['小时'].sum().rename('合计工时')
    # 重新使grouped成为DataFrame以便于后续的计算
    grouped = grouped.reset_index()
    # 按“跟踪”列进行过滤，将bug数据过滤出并计算修改bug的工时
    filter_df = file_content[file_content['跟踪'] == 'Bug-ST'].groupby(['项目', '月份'])['小时'].sum().rename(
        'Bug合计工时')
    # 重新使filter_df成为DataFrame以便于后续的计算
    filter_df = filter_df.reset_index()
    # 将grouped和filter_df进行横向合并，以项目和月份进行关联
    merge_df = pd.merge(grouped, filter_df, on=['项目', '月份'], how='left')
    # 如果'Bug合计工时'中存在空值，默认为0
    merge_df['Bug合计工时'] = merge_df['Bug合计工时'].fillna(0)
    # 对集合按项目进行去重
    unique_project_list = merge_df.drop_duplicates(subset='项目')['项目'].to_list()
    # 创建一个ExcelWriter对象，制定输出文件名
    writer = pd.ExcelWriter('E:/工作文件/运营管理部 项目指标/工作量/运营管理部/' + '各项目COPQ统计（运营管理部）.xlsx')
    # 对集合进行循环遍历后，将不同的项目信息分别保存至不同的sheet页
    for project in unique_project_list:
        # 以项目为条件对merge_df进行过滤
        filter_df = merge_df[merge_df['项目'] == project]
        filter_df = filter_df.reset_index()
        # 新增累积工作量列，内容是逐行合计工时的累加之和
        filter_df['累积工作量'] = filter_df['合计工时'].cumsum()
        # 新增累积Bug工时列，内容是Bug合计工时的累加之和
        filter_df['累积Bug工时'] = filter_df['Bug合计工时'].cumsum()
        filter_df['COPQ'] = filter_df.apply(lambda row: round(row['累积Bug工时'] / row['累积工作量'], 4), axis=1)
        # 将过滤后的数据保存至Excel的sheet页中
        filter_df.to_excel(writer, sheet_name=project, index=False)
    writer.close()

def cal_copq_new(file_content):
    """
    计算COPQ
    """
    # 根据“日期”列生成“月份”列
    file_content['月份'] = file_content['日期'].apply(lambda x: x[:4] + x[5:7])
    # 提取file_content中项目、月份、小时列的数据
    file_content = file_content[['类别', '日期', '小时', '月份', '跟踪']]

    """
    1.因为“汽车数字化项目”存在两个Redmine记录工作量且数据结构并不完全一致，所以此段代码针对旧Redmine的数据进行处理
    2.其他项目不使用可以将此段代码注释掉
    3.从此处开始
    """
    # file_old_content = get_date('E:/工作文件/运营管理部 项目指标/工作量/旧数据/')
    # file_old_content['月份'] = file_old_content['日期'].apply(lambda x: x[:4] + x[5:7])
    # file_old_content['项目'] = 'RD008001.汽车数字化分析'
    # # file_old_content中，“Bug等级”列不为空的，内容更新成“Bug-ST”

    # levels = ['S', 'A', 'B', 'C', 'D']
    # file_old_content.loc[file_old_content['Bug等级'].isin(levels), '跟踪'] = 'Bug-ST'

    # file_old_content = file_old_content[['项目', '日期', '小时', '月份', '跟踪']]
    # # 将file_old_content接在file_content的后面
    # file_content = pd.concat([file_content, file_old_content])
    """
    4.从此处结束
    """

    # 按“项目”和“月份”对file_content中的“小时”列进行汇总
    grouped = file_content.groupby(['类别', '月份'])['小时'].sum().rename('合计工时')
    # 重新使grouped成为DataFrame以便于后续的计算
    grouped = grouped.reset_index()
    # 按“跟踪”列进行过滤，将bug数据过滤出并计算修改bug的工时
    filter_df = file_content[file_content['跟踪'] == 'Bug-ST'].groupby(['类别', '月份'])['小时'].sum().rename(
        'Bug合计工时')
    # 重新使filter_df成为DataFrame以便于后续的计算
    filter_df = filter_df.reset_index()
    # 将grouped和filter_df进行横向合并，以项目和月份进行关联
    merge_df = pd.merge(grouped, filter_df, on=['类别', '月份'], how='left')
    # 如果'Bug合计工时'中存在空值，默认为0
    merge_df['Bug合计工时'] = merge_df['Bug合计工时'].fillna(0)
    # 对集合按项目进行去重
    unique_project_list = merge_df.drop_duplicates(subset='类别')['类别'].to_list()
    # 创建一个ExcelWriter对象，制定输出文件名
    writer = pd.ExcelWriter('E:/工作文件/运营管理部 项目指标/工作量/运营管理部/' + '各子项目COPQ统计（运营管理部）.xlsx')
    # 对集合进行循环遍历后，将不同的项目信息分别保存至不同的sheet页
    for project in unique_project_list:
        # 以项目为条件对merge_df进行过滤
        filter_df = merge_df[merge_df['类别'] == project]
        filter_df = filter_df.reset_index()
        # 新增累积工作量列，内容是逐行合计工时的累加之和
        filter_df['累积工作量'] = filter_df['合计工时'].cumsum()
        # 新增累积Bug工时列，内容是Bug合计工时的累加之和
        filter_df['累积Bug工时'] = filter_df['Bug合计工时'].cumsum()
        filter_df['COPQ'] = filter_df.apply(lambda row: round(row['累积Bug工时'] / row['累积工作量'], 4), axis=1)
        # 将过滤后的数据保存至Excel的sheet页中
        filter_df.to_excel(writer, sheet_name=project, index=False)
    writer.close()

# 在固定的路径下遍历文件夹，获取CSV文件名列表
def get_file_list(path):
    file_list = []
    for root, dirs, files in os.walk(path):
        for file in files:
            # 默认情况下，只读取路径下的CSV类型的文件
            if os.path.splitext(file)[1].lower() == '.csv':
                file_list.append(file)

    return file_list


# 通过地址+文件名列表，使用pandas库分别读取CSV文件内容，生成并返回一个DateFrame对象
def get_file_content(path, file_list, file_encoding):
    # 定义一个DateFrame类型的对象file_content
    file_content = pd.DataFrame()
    for file in file_list:
        # 将查询的结果合并成一个DateFrame类型的对象file_content
        file_content = pd.concat([file_content, pd.read_csv(path + file, encoding=file_encoding)], axis=0)

    return file_content


# 检测CSV文件的编码类型并返回编码类型
def check_file_encoding(file_path):
    with open(file_path, 'rb') as f:
        # 读取文件的前1024个字节作为样本进行检测
        sample = f.read(1024)
        # 使用chardet.detect方法检测文件的编码类型
        encoding_info = chardet.detect(sample)
        encoding = encoding_info.get('encoding')
        return encoding if encoding is not None else "Unknown"


# 定义数据文件的路径
path = 'E:/工作文件/运营管理部 项目指标/工作量/数据/'

# 获取数据
file_content = get_date(path)

# 调用cal_month_data()方法计算每月工作量和累积工作量
cal_month_data(file_content)

# 调用cal_month_childproject函数计算每个子项目的工作量
cal_month_childproject(file_content)

# 调用cal_copq()方法计算COPQ
cal_copq(file_content)
# 调用cal_copq_new()方法计算每个子项目的COPQ
cal_copq_new(file_content)

# 调用cal_lowStars方法计算低星版本率
cal_lowStars(file_content)
